<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>this测试</title>
</head>
<body>
  <script>
    // 返回一个新函数, 新函数内部会通过call来调用原函数, 且指定this为bind的第一个参数对象
    Function.prototype.bind = function (thisObj) {
      return () => {
        return this.call(thisObj)
      }
    }

    fn.bind({})()
  </script>

  <script>
    /* 
    - fn(): 直接调用  ==> **this是?**  window       在严格模式下, 函数中指向window的this都为undefined
    - new fn(): new调用 ==> **this是?**  新建的对象
    - obj.fn(): 通过对象调用 ==> **this是?**  obj  
    - fn.call/apply/bind(obj): 通过函数对象的call/apply/bind来调用 ==> **this是?**  obj
    */
    // 'use strict'
    // function fn(a, b) {
    //   console.log(this)
    // }

    // fn()  // window  / undefined
    // new fn()  // new新创建的实例对象
    // var obj = {fn}
    // obj.fn() // obj
    // const obj2 = {m: 2}
    // fn.call(undefined) // window
    // fn.call(obj2) // obj2
    // console.log('---------')
    // fn.bind(obj2)()  // obj2

    // // 箭头函数  => 没有自己的this, 只能沿着作用域链, 去外部找this
    // var n = 1
    // var obj = {
    //   n: 2,
    //   // m: () => {
    //   m: function () {
    //     console.log(this.n)
    //   }
    // }

    // obj.m()


    


   
  </script>

  <script>
    /* 相关测试题 */

    // 题1
    
   /*  var a = 10
    function foo () {
      console.log(this.a)
    }
    foo() 
    */


    // 题2
    
    
   /* 
    "use strict"   // 在严格模式下, 函数中指向window的this都为undefined
    var a = 10 // var定义的全局变量会成为window的属性
    function foo () { // 全局函数是window的方法
      console.log('this1', this)
      console.log(window.a)
      console.log(this.a) // 输出？
    }
    console.log(window.foo)
    console.log('this2', this)  // ?
    foo()  */

    /* const obj = {
      a: 'abc',
      b: funnction (){}
    }  */
    // 属性值是函数的属性就是方法  / 方法是一类特别的属性, 特别在属性值是函数
   

    // 题3
    
    // let/const的全局变量不会添加为window的属性
    /* let a = 10
    const b = 20

    function foo () {
      console.log(this.a)
      console.log(this.b)
    }
    foo();
    console.log(window.a)  */
   

    // 题4
    
    /* var a = 1
    function foo () {
      // this是window
      var a = 2
      var inner = () => { 
        console.log(a, this.a)  // 使用外部的this
      }
      inner()
    }
    foo()  */
   

    // 题5
    
   /*  function foo () {
      console.log(this.a)
    }
    var obj = { a: 1, foo: foo }
    var a = 2
    obj.foo() 
    */

    // 题6
    
    /* function foo () {
      console.log(this.a)
    };
    var obj = { a: 1, foo }
    var a = 2
    var foo2 = obj.foo
    var obj2 = { a: 3, foo2: obj.foo }

    obj.foo()  // 通过对象
    foo2()  // 直接调用
    obj2.foo2()  // 通过对象 */
   


    // 题7
    
    /* function foo () {
      console.log(this.a)
      return function () {
        console.log(this.a)
      }
    }
    var obj = { a: 1 }
    var a = 2

    foo() // 2
    foo.call(obj) // 1
    foo().call(obj) // 2 1 */
   


    // 题8
    
   /* function foo () {
      console.log(this.a)
      return function () {
        console.log(this.a)
      }
    }
    var obj = { a: 1 }
    var a = 2

    foo() // 2
    foo.bind(obj) // 
    foo().bind(obj) // 2  */
   

    // 题9
    
    /* var obj = {
      name: 'obj',
      foo1: () => {
        console.log(this.name)
      },
      foo2: function () {
        console.log(this.name)
        // return function () {
        return () => {
          console.log(this.name)
        }
      }
    }
    var name = 'window'
    obj.foo1() // window
    obj.foo2()() // obj obj */

    // 题 10
    function Foo() {
      getName = function() { console.log(1) }
      return this
    }

    Foo.getName = function() { console.log(2) }
    Foo.prototype.getName = function() { console.log(3) }

    var getName = function() { console.log(4) }
    function getName () { console.log(5)  }

    Foo.getName() // 2   静态方法: 函数对象本身的方法
    getName() // 4
    Foo().getName() // 1
    getName()  // 1
    new Foo.getName() // 2
    new Foo().getName() // 3
</script>
</body>
</html>